package com.ruoyi.project.wenyanwen.generate.task.impl;

import com.ruoyi.common.constant.DbGenerateCommand;
import com.ruoyi.common.constant.DbGenerateResult;
import com.ruoyi.common.constant.DbGenerateStatus;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.Md5Utils;
import com.ruoyi.framework.config.RuoYiConfig;
import com.ruoyi.project.wenyanwen.export.service.ISqliteExportService;
import com.ruoyi.project.wenyanwen.generate.domain.DbGenerate;
import com.ruoyi.project.wenyanwen.generate.domain.GenerateTask;
import com.ruoyi.project.wenyanwen.generate.domain.TaskMonitor;
import com.ruoyi.project.wenyanwen.generate.service.IDbGenerateService;
import com.ruoyi.project.wenyanwen.generate.task.DbGenerateTask;
import com.ruoyi.project.wenyanwen.generatelog.domain.DbGenerateLog;
import com.ruoyi.project.wenyanwen.generatelog.service.IDbGenerateLogService;
import jodd.io.FileUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Component
public class DbGenerateTaskImpl implements DbGenerateTask {


    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;

    protected static Log logger = LogFactory.getLog(DbGenerateTaskImpl.class);

    private Map<String, String> commands = new ConcurrentHashMap<String, String>();

    @Autowired
    IDbGenerateService dbGenerateService;

    @Autowired
    IDbGenerateLogService dbGenerateLogService;

    @Autowired
    ISqliteExportService sqliteExportService;

    @Override
    public void main() {

        try {

            DbGenerate task = dbGenerateService.getTask();

            if (task == null) {
                logger.info("not task now");
                return;
            }

            this.handle(task);

        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
    }


    private void handle(final DbGenerate dbGenerate) {

        Runnable task = new Runnable() {

            @Override
            public void run() {
                try {
                    _handle(dbGenerate);
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                    dbGenerate.setErrorLog(e.getMessage());
                    dbGenerate.setLastResult(DbGenerateResult.FAILURE);
                    dbGenerate.setStatus(DbGenerateStatus.FINISH);
                    dbGenerateService.updateDbGenerate(dbGenerate);
                }
            }
        };

        taskExecutor.execute(task);

    }

    private TaskMonitor taskMonitor(final String dbName) {

        return new TaskMonitor() {

            @Override
            public boolean isStop() {

                String command = commands.remove(dbName);
                if (StringUtils.equals(command, DbGenerateCommand.STOP)) {
                    return true;
                }
                return false;
            }
        };

    }

    /**
     * 停止生成包的任务
     *
     * @param dbGenerate
     */
    private void _stop(DbGenerate dbGenerate) {
        // 停止任务
        commands.put(dbGenerate.getDbName(), dbGenerate.getCommand());
    }

    private void _handle(DbGenerate dbGenerate) throws Exception {

        if (StringUtils.equalsIgnoreCase(dbGenerate.getCommand(), DbGenerateCommand.STOP)) {
            this._stop(dbGenerate);
        } else {
            commands.remove(dbGenerate.getDbName());
            this._generate(dbGenerate);
        }

    }

    /**
     * 生成包
     *
     * @param dbGenerate
     * @throws IOException
     */
    private void _generate(DbGenerate dbGenerate) throws IOException {

        GenerateTask task = new GenerateTask();
        task.setDbGenerate(dbGenerate);
        task.setMonitor(taskMonitor(dbGenerate.getDbName()));
        int total = this.sqliteExportService.getCount(dbGenerate.getDbName());
        task.setTotal(total);

        final String dbName = dbGenerate.getDbName();

        String ver = DateUtils.parseDateToStr("yyyyMMddHHmmss", DateUtils.getNowDate());

        String dbTempName = dbName.replace(".db", "-") + ver + ".db";
        String dbDayPath = DateUtils.parseDateToStr("yyyy-MM-dd", DateUtils.getNowDate());

        String dbPath = RuoYiConfig.getPackagePath() + dbDayPath + "/" + dbTempName;
        task.setDbPath(dbPath);
        task.setVersion(dbGenerate.getVersion());

        FileUtil.mkdir(RuoYiConfig.getPackagePath() + dbDayPath);

        try {
            this.sqliteExportService.export(task);
        } catch (Exception e) {
            task.setResult(DbGenerateResult.FAILURE);
            task.setErrorMsg(e.getMessage());
            logger.error(e.getMessage(), e);
        }

        task.setEnd(System.currentTimeMillis());

        dbGenerate.setStatus(task.getStatus());
        if (task.getResult() == DbGenerateResult.SUCCESS) {
            dbGenerate.setLastPackage(dbDayPath + "/" + dbTempName);
            dbGenerate.setLastUseTime((long) task.getUseTime());
            dbGenerate.setProgress((long) 100);
        }
        dbGenerate.setLastResult(task.getResult());

        dbGenerate.setLastTime(DateUtils.getNowDate());
        dbGenerate.setErrorLog(task.getErrorMsg());

        this.dbGenerateService.updateDbGenerate(dbGenerate);

        if (task.getResult() == DbGenerateResult.SUCCESS) {

            String fullPath = RuoYiConfig.getPackagePath() + dbDayPath + "/" + dbTempName;
            File file = new File(fullPath);
            String md5 = Md5Utils.md5(file);
            long size = file.length();

            DbGenerateLog dbGenerateLog = new DbGenerateLog();
            dbGenerateLog.setCreatedTime(DateUtils.getNowDate());
            dbGenerateLog.setCreatedUser(dbGenerate.getCommandUser());
            dbGenerateLog.setDbName(dbName);
            dbGenerateLog.setFileName(dbDayPath + "/" + dbTempName);
            dbGenerateLog.setMd5(md5);
            dbGenerateLog.setSize((long) size);
            dbGenerateLog.setVersion(dbGenerate.getVersion());

            this.dbGenerateLogService.insertDbGenerateLog(dbGenerateLog);
        }
    }

    @PostConstruct
    public void init() {

        new Thread(new Runnable() {

            @Override
            public void run() {
                while (true) {
                    main();
                }
            }
        }).start();

    }
}
